package org.hong.monkey.metrics

import java.io.{FileInputStream, InputStream}
import java.util.Properties

import org.hong.monkey.util.Utils
import org.hong.monkey.{Logging, MonkeyConf}

import scala.collection._
import scala.collection.JavaConverters._
import scala.util.matching.Regex

/**
 */
private[monkey] class MetricsConfig(conf: MonkeyConf) extends Logging {

  private val DEFAULT_PREFIX = "*"
  private val INSTANCE_REGEX = "^(\\*|[a-zA-Z]+)\\.(.+)".r
  private val DEFAULT_METRICS_CONF_FILNAME = "metrics.properties"

  private[metrics] val properties = new Properties()
  private[metrics] var propertyCategories: mutable.HashMap[String, Properties] = null

  private def setDefaultProperties(prop: Properties) {
    prop.setProperty("*.sink.servlet.class", "org.hong.monkey.metrics.sink.MetricsServlet")
    prop.setProperty("*.sink.servlet.path", "/metrics/json")
    prop.setProperty("master.sink.servlet.path", "/metrics/master/json")
    prop.setProperty("applications.aink.servlet.path", "/metrics/applications/json")
  }

  def initialize() {
    setDefaultProperties(properties)

    loadPropertiesFromFile(conf.getOption("monkey.metrics.conf"))

    val prefix = "monkey.metrics.conf."
    conf.getAll.foreach {
      case (k, v) if k.startsWith(prefix) =>
        properties.setProperty(k.substring(prefix.length), v)
      case _ =>
    }

    propertyCategories = subProperties(properties, INSTANCE_REGEX)
    if (propertyCategories.contains(DEFAULT_PREFIX)) {
      val defaultProperty = propertyCategories(DEFAULT_PREFIX).asScala
      for ((inst, prop) <- propertyCategories if (inst != DEFAULT_PREFIX);
           (k, v) <- defaultProperty if (prop.get(k) == null)) {
        prop.put(k, v)
      }
    }
  }

  def subProperties(prop: Properties, regex: Regex): mutable.HashMap[String, Properties] = {
    val subProperties = new mutable.HashMap[String, Properties]
    prop.asScala.foreach { kv =>
      if (regex.findPrefixOf(kv._1.toString).isDefined) {
        val regex(prefix, suffix) = kv._1.toString
        subProperties.getOrElseUpdate(prefix, new Properties).setProperty(suffix, kv._2.toString)
      }
    }
    subProperties
  }

  def getInstance(inst: String): Properties = {
    propertyCategories.get(inst) match {
      case Some(s) => s
      case None => propertyCategories.getOrElse(DEFAULT_PREFIX, new Properties)
    }
  }

  private[this] def loadPropertiesFromFile(path: Option[String]) {
    var is: InputStream = null
    try {
      is = path match {
        case Some(f) => new FileInputStream(f)
        case None => Utils.getMonkeyClassLoader.getResourceAsStream(DEFAULT_METRICS_CONF_FILNAME)
      }

      if (is != null)
        properties.load(is)
    } catch {
      case e: Exception =>
        val file = path.getOrElse(DEFAULT_METRICS_CONF_FILNAME)
        logError(s"Error loading metrics configuration file $file")
    } finally {
      if (is != null)
        is.close()
    }
  }

}
